﻿using Common;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using jq9602_jq9603.Process;

//using Masuit.Tools;

//using Masuit.Tools;
using NewDevice;
using NewDevice.RS232;
using NewDevice.RS485;
using NewDevice.TCPIP;
using OfficeOpenXml;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Data;
using System.Windows.Shapes;
using Masuit.Tools;
using Path = System.IO.Path;

namespace jq9602_jq9603.ViewModel
{
    internal partial class MainViewModel : ObservableObject
    {
        public event EventHandler? CloseRequested;

        [RelayCommand]
        public void WindowClosed(object obj)
        {
            _isRun = false;

            CloseRequested?.Invoke(this, EventArgs.Empty);
        }

        private void InitAllDo()
        {
            try
            {
                SetDo(DoDefine.AcPosPower, false);
                SetDo(DoDefine.AcNegPower, false);
                SetDo(DoDefine.DcPosPower, false);
                SetDo(DoDefine.DcNegPower, false);
                SetDo(DoDefine.Rk9310Con1, false);
                SetDo(DoDefine.Rk9310Con2, false);
                SetDo(DoDefine.Rk9310Con3, false);
                SetDo(DoDefine.Rk9310Con4, false);
            }
            catch (Exception ex)
            {
                MyLog.Error(ex);
                AppendLog(ex.Message);
            }
        }

        #region Device

        private IoModule IoModule = null!;
        private ZH_40061_14N1_V2 AcCard = null!;
        private ZhT08R14N1_V2 ResCard = null!;
        private Zh3412134M2_V2 DcCard = null!;
        private RK9310 RK9310 = null!;

        #endregion Device

        private void InitDevice()
        {
            IoModule = new IoModule();
            IoModule.Connect(GlobalValue.Config.GetParams("IO采集卡IP地址"));
            _ = UpdateDiDo();
#pragma warning disable CS8625
            IoModule.ListDiChanged.Add(new DiChanged(new Action(() => { Start(null); })) { DIndex = 0, ConditionValue = true });
            IoModule.ListDiChanged.Add(new DiChanged(new Action(() => { _isEmgStop = false; })) { DIndex = 1, ConditionValue = true });
            IoModule.ListDiChanged.Add(new DiChanged(new Action(() => { _isEmgStop = true; _emgStopTokenSource?.Cancel(); })) { DIndex = 1, ConditionValue = false });
            IoModule.ListDiChanged.Add(new DiChanged(new Action(() => { Reset(null); })) { DIndex = 2, ConditionValue = true });
#pragma warning restore CS8625

            AcCard = new ZH_40061_14N1_V2(GlobalValue.Config.GetParams("交流电流采集卡端口"))
            {
                MeasureRange = 500
            };
            AcCard.Open();

            DcCard = new Zh3412134M2_V2(GlobalValue.Config.GetParams("直流电流采集卡IP地址"), int.Parse(GlobalValue.Config.GetParams("直流电流采集卡端口")))
            {
                MeasureRange = 300
            };
            DcCard.Open();

            ResCard = new(GlobalValue.Config.GetParams("电阻采集卡端口"));
            ResCard.Open();

            RK9310 = new RK9310();
            RK9310.Connect(GlobalValue.Config.GetParams("RK9310采集卡端口"), 115200);

            ReadAirSignal();
            AppendLog("设备初始化完成");
        }

        private async Task UpdateDiDo()
        {
            while (_isRun)
            {
                foreach (var item in DiDoStatuses)
                {
                    if (item.IsDo)
                    {
                        item.SetStatusFromBackend(IoModule.GetDoValue(item.ChannelIndex));
                    }
                    else
                    {
                        item.SetStatusFromBackend(IoModule.GetDiValue(item.ChannelIndex));
                    }
                }
                await Task.Delay(500);
            }
        }

        [RelayCommand]
        private void ResetCount(object obj)
        {
            PassCount = 0;
            NgCount = 0;
        }

        private bool _isError = false;

        [RelayCommand]
        private void Start(object obj)
        {
            if (_isTesting)
            {
                return;
            }
            _isTesting = true;
            if (_isBusy)
            {
                _isTesting = false;
                AppendLog("正在进行其他操作,请完成后再操作");
                return;
            }

            _isBusy = true;
            Task.Run(() =>
            {
                _isError = false;
                try
                {
                    if (_isEmgStop)
                    {
                        throw new Exception("设备急停");
                    }
                    Stopwatch sw = Stopwatch.StartNew();
                    _dataDtail.Clear();
                    TestJq960X();
                    for (int i = 0; i < TotalResult.Count; i++)
                    {
                        TotalResult[i] = Products.All(x => x.StationIsPassed[i] == true);
                    }

                    if (TotalResult.All(x => x == true))
                    {
                        SetDo(DoDefine.Pass, true);
                        SetDo(DoDefine.Ng, false);
                    }
                    else
                    {
                        SetDo(DoDefine.Pass, false);
                        SetDo(DoDefine.Ng, true);
                    }
                    PassCount += TotalResult.Count(x => x == true);
                    NgCount += TotalResult.Count(x => x == false);

                    AppendLog($"测试耗时{(int)sw.Elapsed.TotalSeconds}s");
                }
                catch (Exception ex)
                {
                    SetDo(DoDefine.Pass, false);
                    SetDo(DoDefine.Ng, true);
                    _isError = true;
                    AppendLog(ex.Message + "!");
                    MyLog.Error(ex);
                }
                finally
                {
                    InitAllDo();
                    try
                    {
                        GenerateReport(Products, _dataDtail);
                        AppendLog("生成测试报告");
                    }
                    catch (Exception ex)
                    {
                        AppendLog(ex.Message);
                    }
                    _isTesting = false;
                    _isBusy = false;
                }

                //if (_isError)
                //{
                //    ExportDebugData("EeceptionTimeData" + DateTime.Now.ToString("yyyyMMdd HHmmss")).Wait();
                //}
            });
        }

        public bool IsPowerOn => IoModule.GetDoValue(0) || IoModule.GetDoValue(1) || IoModule.GetDoValue(2) || IoModule.GetDoValue(3);

        private void SetDo(DoDefine define, bool status)
        {
            AppendLog($"SetDo[{Enum.GetName(typeof(DoDefine), define)}] [{status}] ");
            IoModule.SetDoValue((int)define, status ? 1 : 0);
        }

        private double GetConfigDoubleParam(string key) => double.Parse(GlobalValue.Config.GetParams(key));

        private string GetConfigStringParam(string key) => GlobalValue.Config.GetParams(key);

        private double ExtractNumber(string input)
        {
            // 匹配整数或小数（包括科学计数法）
            Match match = Regex.Match(input, @"[-+]?\d*\.?\d+([eE][-+]?\d+)?");

            if (match.Success && double.TryParse(match.Value, out double number))
            {
                return number;
            }

            throw new FormatException($"无法从字符串 '{input}' 中提取有效数字");
        }

        private void Delay(int milliseconds)
        {
            var sw = Stopwatch.StartNew();
            while (sw.ElapsedMilliseconds < milliseconds)
            {
                _emgStopTokenSource?.Token.ThrowIfCancellationRequested();
                Thread.SpinWait(10);
            }
        }

        private void TestCurrent(string powerType = "正向")
        {
            Stopwatch sw = Stopwatch.StartNew();
            MyLog.Info($"{nameof(TestCurrent)} {powerType} start");
            for (int i = 0; i < 3; i++)
            {
                MyLog.Info($"{nameof(TestCurrent)} {powerType} for i={i} start---0 sw={sw.ElapsedMilliseconds}ms");
                StartMonitorAirSignal();
                Dictionary<int, List<double>> dataCopy;

                if (SelectedProduct == Jq9602Desc)
                {
                    DcCard.StartNote();

                    DoDefine power = powerType == "正向" ? DoDefine.DcPosPower : DoDefine.DcNegPower;

                    MyLog.Info($"{nameof(TestCurrent)} {powerType} for i={i} start---1 sw={sw.ElapsedMilliseconds}ms");
                    for (int j = 0; j < 2; j++)
                    {
                        SetDo(power, true);
                        Delay(350);
                        SetDo(power, false);
                        Delay(250);
                    }

                    MyLog.Info($"{nameof(TestCurrent)} {powerType} for i={i} start---2 sw={sw.ElapsedMilliseconds}ms");
                    Delay(1000);
                    DcCard.StopNote();
                    MyLog.Info($"{nameof(TestCurrent)} {powerType} for i={i} start---3 sw={sw.ElapsedMilliseconds}ms");
                    StopMonitorAirSignal();
                    MyLog.Info($"{nameof(TestCurrent)} {powerType} for i={i} start---4 sw={sw.ElapsedMilliseconds}ms");
                    dataCopy = DcCard.RegisterValues.DeepClone();
                    MyLog.Info($"{nameof(TestCurrent)} {powerType} for i={i} start---5 sw={sw.ElapsedMilliseconds}ms data_count={dataCopy[0].Count}");
                }
                else
                {
                    AcCard.StartNote();

                    DoDefine power = powerType == "正向" ? DoDefine.AcPosPower : DoDefine.AcNegPower;

                    SetDo(power, true);
                    Delay(1500);
                    SetDo(power, false);
                    Delay(1000);
                    AcCard.StopNote();
                    StopMonitorAirSignal();
                    dataCopy = AcCard.RegisterValues.DeepClone();
                }

                for (int j = 0; j < 4; j++)
                {
                    MyLog.Info($"{nameof(TestCurrent)} {powerType} for i={i} start---6 sw={sw.ElapsedMilliseconds}ms");
                    _dataDtail.Add($"{powerType}供电阶段{i + 1}工位{j + 1}电流", dataCopy[j]);
                    var analyzerResult = _phaseAnalyzer.Analyze(dataCopy[j]);
                    MyLog.Info($"{nameof(TestCurrent)} {powerType} for i={i} start---7 sw={sw.ElapsedMilliseconds}ms data_count={dataCopy[0].Count}");
                    analyzerResult.PrintReport();

                    AppendLog($"阶段[{i + 1}] {dataCopy[j].Count}组数据待处理");
                    AppendLog($"工位[{j + 1}]{powerType}供电阶段[{i + 1}] 匹配到{analyzerResult.Phases.Count}个模式");
                    if (SelectedProduct == Jq9602Desc)
                    {
                        if (analyzerResult.Phases.Count == 0)
                        {
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-1启动电流", j, -1);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-1稳定电流", j, -1);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-1稳定耗时", j, -1);

                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-2启动电流", j, -1);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-2稳定电流", j, -1);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-2稳定耗时", j, -1);
                        }
                        else if (analyzerResult.Phases.Count == 1)
                        {
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-1启动电流", j, analyzerResult.Phases[0].PeakValue);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-1稳定电流", j, analyzerResult.Phases[0].StableValue);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-1稳定耗时", j, analyzerResult.Phases[0].DurationMs);

                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-2启动电流", j, -1);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-2稳定电流", j, -1);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-2稳定耗时", j, -1);
                        }
                        else if (analyzerResult.Phases.Count >= 2)
                        {
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-1启动电流", j, analyzerResult.Phases[0].PeakValue);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-1稳定电流", j, analyzerResult.Phases[0].StableValue);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-1稳定耗时", j, analyzerResult.Phases[0].DurationMs);

                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-2启动电流", j, analyzerResult.Phases[1].PeakValue);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-2稳定电流", j, analyzerResult.Phases[1].StableValue);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}-2稳定耗时", j, analyzerResult.Phases[1].DurationMs);
                        }
                    }
                    else
                    {
                        if (analyzerResult.Phases.Count == 0)
                        {
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}启动电流", j, -1);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}稳定电流", j, -1);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}稳定耗时", j, -1);
                        }
                        else if (analyzerResult.Phases.Count >= 1)
                        {
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}启动电流", j, analyzerResult.Phases[0].PeakValue);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}稳定电流", j, analyzerResult.Phases[0].StableValue);
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}稳定耗时", j, analyzerResult.Phases[0].DurationMs);
                        }
                    }

                    {
                        _dataDtail.Add($"{powerType}供电阶段{i + 1}工位{j + 1}气压信号", _airSignals[j].Select(x => (double)x).ToList());
                        SelectedItem = Products.FindByDesc($"{powerType}供电阶段{i + 1}气压监控");
                        if (BinaryPulseDetector.HasExactlyPulses(_airSignals[j]))
                        {
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}气压监控", j, 0);
                        }
                        else
                        {
                            Products.SetItemResult($"{powerType}供电阶段{i + 1}气压监控", j, -1);
                        }
                    }
                }
            }

            MyLog.Info($"{nameof(TestCurrent)} {powerType} end 耗时{sw.ElapsedMilliseconds}ms");
        }

        //绝缘耐压测试
        // 0 - 绝缘测试
        // 1 - 耐压测试
        private void TestJyny(int mode)
        {
            string itemDesc;
            if (mode == 0)
            {
                itemDesc = "绝缘测试";
                var voltage = GetConfigDoubleParam($"{SelectedProduct}绝缘测试电压");
                var time = GetConfigDoubleParam($"{SelectedProduct}绝缘测试时间");
                var dnlm = GetConfigDoubleParam($"{SelectedProduct}绝缘阻值下限");

                RK9310.IrInit(voltage, time, 0, dnlm);
            }
            else
            {
                itemDesc = "耐压测试";
                var voltage = GetConfigDoubleParam($"{SelectedProduct}耐压测试电压");
                var time = GetConfigDoubleParam($"{SelectedProduct}耐压测试时间");
                var uplm = GetConfigDoubleParam($"{SelectedProduct}耐压电流上限");

                RK9310.DcInit(voltage, time, uplm, 0);
            }
            SelectedItem = Products.FindByDesc(itemDesc);

            SetDo(DoDefine.Rk9310Con1, true);
            SetDo(DoDefine.Rk9310Con2, true);
            SetDo(DoDefine.Rk9310Con3, true);
            SetDo(DoDefine.Rk9310Con4, true);

            Delay(TimeDelay);
            // 整体测试， 测试失败后单独测试
            (string msg, bool _) = RK9310.StartTest(_emgStopTokenSource.Token);
            double value = ExtractNumber(msg);

            Products.SetItemResult(itemDesc, value);

            // 如果测试失败则单独测
            if (SelectedItem.StationIsPassed[0] == false)
            {
                for (int i = 0; i < TestItem.StationCount; i++)
                {
                    SetDo(DoDefine.Rk9310Con1, i + DoDefine.Rk9310Con1 == DoDefine.Rk9310Con1);
                    SetDo(DoDefine.Rk9310Con2, i + DoDefine.Rk9310Con1 == DoDefine.Rk9310Con2);
                    SetDo(DoDefine.Rk9310Con3, i + DoDefine.Rk9310Con1 == DoDefine.Rk9310Con3);
                    SetDo(DoDefine.Rk9310Con4, i + DoDefine.Rk9310Con1 == DoDefine.Rk9310Con4);
                    Delay(TimeDelay);
                    (msg, _) = RK9310.StartTest(_emgStopTokenSource.Token);
                    value = ExtractNumber(msg);
                    Products.SetItemResult(itemDesc, i, value);
                }
            }

            SetDo(DoDefine.Rk9310Con1, false);
            SetDo(DoDefine.Rk9310Con2, false);
            SetDo(DoDefine.Rk9310Con3, false);
            SetDo(DoDefine.Rk9310Con4, false);
        }

        private void TestJq960X()
        {
            // ui init
            for (int i = 0; i < TotalResult.Count; i++)
            {
                TotalResult[i] = null;
            }
            Products.Init();

            // init do
            InitAllDo();
            SetDo(DoDefine.Pass, true);
            SetDo(DoDefine.Ng, false);

            _emgStopTokenSource = new CancellationTokenSource();
            // 接地导通测试
            {
                SelectedItem = Products.FindByDesc("接地导通");

                ResCard.StartNote();
                Thread.Sleep(1000);
                ResCard.StopNote();

                if (ResCard.RegisterValues[0].Count == 0)
                {
                    //AppendLog("电阻采集卡读到{0}条数据");
                    throw new Exception("电阻采集卡读到0条数据");
                }
                Dictionary<int, List<double>> resData = ResCard.RegisterValues.DeepClone();
                for (int i = 0; i < TestItem.StationCount; i++)
                {
                    var count = resData[i].Count;
                    AppendLog($"工位[{i + 1}]电阻读值共{count}条数据");
                    if (resData[i].Count > 0)
                    {
                        AppendLog($"电阻读值:{string.Join(",", resData[i])}");
                    }
                    _dataDtail.Add($"工位{i + 1}阻值", resData[i]);

                    resData[i].Sort();

                    Products.SetItemResult("接地导通", i, resData[i].Average());
                }
            }

            // 绝缘测试
            TestJyny(0);

            // 耐压测试
            TestJyny(1);

#if TEST_ALL_CLIENT
            TestCurrent("正向");
            TestCurrent("反向");
#endif
        }

        [RelayCommand]
        private void Reset(object obj)
        {
            if (_isBusy)
            {
                AppendLog("正在进行其他操作,请完成后再操作");
                return;
            }

            Task.Run(() =>
            {
                _isBusy = true;
                try
                {
                    for (int i = 0; i < TotalResult.Count; i++)
                    {
                        TotalResult[i] = null;
                    }
                    Products.Init();
                    // init do
                    InitAllDo();
                    SetDo(DoDefine.Pass, true);
                    SetDo(DoDefine.Ng, false);

                    AppendLog("复位完成");
                }
                catch (Exception ex)
                {
                    AppendLog(ex.Message);
                }
                finally
                {
                    _isBusy = false;
                }
            });
        }

        [RelayCommand]
        private async Task WindowLoadAsync()
        {
            await Task.Delay(0);
            try
            {
                PassCount = 0;
                NgCount = 0;
                GlobalValue.DiDoDefine.ParseFile("config.xlsx", "IO定义");
                GlobalValue.Config.ParseFile("config.xlsx", "参数配置");

                SelectedProduct = GlobalValue.Config.GetParams("当前测试产品类型");
                foreach (var item in GlobalValue.DiDoDefine.ParamList)
                {
                    string key = item.Key;
                    int value = int.Parse(item.Value);
                    bool isDo = key.Contains("DO");
                    DiDoStatuses.Add(new DiDoStatus { ChannelIndex = value, Description = key, IsDo = isDo, Status = true, StatusChanged = IoStatusChanged });
                }
                AppendLog("配置加载完成");
#pragma warning disable CS4014
                UpdateSystemTime();
#pragma warning restore CS4014
                InitDevice();
            }
            catch (Exception e)
            {
                AppendLog(e.Message);
                MyLog.Error(e);
            }
        }

        private void IoStatusChanged(object sender, bool oldValue, bool newValue)
        {
            var io = sender as DiDoStatus;
#pragma warning disable CS8602
            if (!io.IsUpdatingFromBackend && io.IsDo)
            {
                if (io.ChannelIndex < 4 && IsPowerOn && newValue)
                {
                }
                else
                {
                    IoModule.SetDoValue(io.ChannelIndex, newValue ? 1 : 0);
                }
            }
#pragma warning restore CS8602
        }

        partial void OnSelectedItemChanged(TestItem? value)
        {
            AppendLog($"当前项[{value?.Desc}]");
        }

        [RelayCommand]
        private async Task UpdateDiDoStatuses()
        {
            await Task.Delay(10);
            foreach (var t in DiDoStatuses)
            {
                t.Status = !t.Status;
            }
        }

        private void GenerateReport(Products products, Dictionary<string, List<double>> reportDetail)
        {
            var outputDirectory = GlobalValue.Config.GetParams("测试报告路径");
            if (Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }
            string fileName = $"{SelectedProduct}_{DateTime.Now:yyyyMMdd_HHmmss}{(_isError ? "_error" : "")}.xlsx";
            string filePath = Path.Combine(outputDirectory, fileName);
            AppendLog($"输出测试报告[{filePath}]");

            {
                ExcelPackage.License.SetNonCommercialOrganization("BoYao");

                using ExcelPackage package = new ExcelPackage(filePath);
                package.Workbook.Worksheets.Add("total");
                package.Workbook.Worksheets.Add("detail");

                // 第一页 总览数据
                ExcelWorksheet sheet = package.Workbook.Worksheets[0];

                int row = 1;
                int col = 1;

                // 表头
                sheet.Cells[row, col++].Value = "测试项";
                sheet.Cells[row, col++].Value = "工位1实测值";
                sheet.Cells[row, col++].Value = "工位2实测值";
                sheet.Cells[row, col++].Value = "工位3实测值";
                sheet.Cells[row, col++].Value = "工位4实测值";
                sheet.Cells[row, col++].Value = "下限";
                sheet.Cells[row, col++].Value = "上限";
                sheet.Cells[row, col++].Value = "工位1测试结果";
                sheet.Cells[row, col++].Value = "工位2测试结果";
                sheet.Cells[row, col++].Value = "工位3测试结果";
                sheet.Cells[row, col++].Value = "工位4测试结果";

                foreach (var item in products)
                {
                    row++;
                    col = 1;
                    sheet.Cells[row, col++].Value = item.Desc;
                    sheet.Cells[row, col++].Value = item.S1DisplayValue;
                    sheet.Cells[row, col++].Value = item.S2DisplayValue;
                    sheet.Cells[row, col++].Value = item.S3DisplayValue;
                    sheet.Cells[row, col++].Value = item.S4DisplayValue;
                    sheet.Cells[row, col++].Value = item.DisplayMinLimit;
                    sheet.Cells[row, col++].Value = item.DisplayMaxLimit;
                    sheet.Cells[row, col++].Value = item.StationIsPassed[0] == true ? "PASS" : "NG";
                    sheet.Cells[row, col++].Value = item.StationIsPassed[1] == true ? "PASS" : "NG";
                    sheet.Cells[row, col++].Value = item.StationIsPassed[2] == true ? "PASS" : "NG";
                    sheet.Cells[row, col++].Value = item.StationIsPassed[3] == true ? "PASS" : "NG";
                }
                row++;
                sheet.Cells[row, 1].Value = "总结果";
                col = 8;
                foreach (var item in TotalResult)
                {
                    sheet.Cells[row, col++].Value = item == true ? "PASS" : "NG";
                }

                sheet.Cells.AutoFitColumns();
                // 第二页 详细数据
                sheet = package.Workbook.Worksheets[1];

                sheet.Name = "detail";
                row = 1;
                col = 1;
                foreach (var item in reportDetail)
                {
                    sheet.Cells[row++, col].Value = item.Key;
                    foreach (var data in item.Value)
                    {
                        sheet.Cells[row++, col].Value = data;
                    }
                    col++;
                    row = 1;
                }
                sheet.Cells.AutoFitColumns();
                package.Save();
            }
        }

        private void ExportDictionaryToCsv(Dictionary<int, List<double>> data, string title, string outputDirectory)
        {
            // 1. 确定输出目录
            if (string.IsNullOrEmpty(outputDirectory))
            {
                outputDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            }
            if (!Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }

            // 2. 创建文件名（当前时间格式）
            string fileName = $"{title}_{DateTime.Now:yyyyMMdd_HHmmss}.csv";
            string filePath = Path.Combine(outputDirectory, fileName);

            // 3. 准备CSV内容
            var csvContent = new StringBuilder();

            try
            {
                // 4. 确保目录存在
                Directory.CreateDirectory(outputDirectory);

                // 5. 获取所有键（列名）
                var keys = data.Keys.OrderBy(k => k).ToList();

                // 6. 写入表头（列名）
                csvContent.AppendLine(string.Join(",", keys.Select(k => $"Column_{k}")));

                // 7. 确定最大行数（以最长的列表为准）
                int maxRows = data.Values.Max(list => list?.Count ?? 0);

                // 8. 写入数据行
                for (int row = 0; row < maxRows; row++)
                {
                    var rowValues = new List<string>();

                    foreach (var key in keys)
                    {
                        if (data.TryGetValue(key, out var list) && row < list.Count)
                        {
                            // 格式化为带小数点的数字
                            rowValues.Add(list[row].ToString(CultureInfo.InvariantCulture));
                        }
                        else
                        {
                            // 数据缺失时留空
                            rowValues.Add("");
                        }
                    }

                    csvContent.AppendLine(string.Join(",", rowValues));
                }

                // 9. 写入文件（UTF-8带BOM确保Excel兼容）
                File.WriteAllText(filePath, csvContent.ToString(), Encoding.UTF8);
            }
            catch (Exception ex)
            {
                AppendLog($"导出CSV失败: {ex.Message}!");
            }
        }

        private void ExportDictionaryToCsv(Dictionary<int, List<int>> data, string title, string outputDirectory)
        {
            // 1. 确定输出目录
            if (string.IsNullOrEmpty(outputDirectory))
            {
                outputDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            }
            if (!Directory.Exists(outputDirectory))
            {
                Directory.CreateDirectory(outputDirectory);
            }

            // 2. 创建文件名（当前时间格式）
            string fileName = $"{title}_{DateTime.Now:yyyyMMdd_HHmmss}.csv";
            string filePath = Path.Combine(outputDirectory, fileName);

            if (data.Count == 0)
            {
                return;
            }

            // 3. 准备CSV内容
            var csvContent = new StringBuilder();

            try
            {
                // 4. 确保目录存在
                Directory.CreateDirectory(outputDirectory);

                // 5. 获取所有键（列名）
                var keys = data.Keys.OrderBy(k => k).ToList();

                // 6. 写入表头（列名）
                csvContent.AppendLine(string.Join(",", keys.Select(k => $"Column_{k}")));

                // 7. 确定最大行数（以最长的列表为准）
                int maxRows = data.Values.Max(list => list?.Count ?? 0);

                // 8. 写入数据行
                for (int row = 0; row < maxRows; row++)
                {
                    var rowValues = new List<string>();

                    foreach (var key in keys)
                    {
                        if (data.TryGetValue(key, out var list) && row < list.Count)
                        {
                            rowValues.Add(list[row].ToString());
                        }
                        else
                        {
                            // 数据缺失时留空
                            rowValues.Add("");
                        }
                    }

                    csvContent.AppendLine(string.Join(",", rowValues));
                }

                // 9. 写入文件（UTF-8带BOM确保Excel兼容）
                File.WriteAllText(filePath, csvContent.ToString(), Encoding.UTF8);
            }
            catch (Exception ex)
            {
                AppendLog($"导出CSV失败: {ex.Message}!");
            }
        }

        [RelayCommand]
        private async Task ExportDebugData(string name = "")
        {
            try
            {
                var data = ResCard.RegisterValues;
                await Task.Run(() => { ExportDictionaryToCsv(data, $"Res_{name}", "D:\\Output\\Debug"); });

                if (SelectedProduct == Jq9602Desc)
                {
                    data = DcCard.RegisterValues;
                    await Task.Run(() => { ExportDictionaryToCsv(data, $"DC_{name}", "D:\\Output\\Debug"); });
                }
                else
                {
                    data = AcCard.RegisterValues;
                    await Task.Run(() => { ExportDictionaryToCsv(data, $"AC_{name}", "D:\\Output\\Debug"); });
                }

                await Task.Run(() => { ExportDictionaryToCsv(_airSignals, $"Air_{name}", "D:\\Output\\Debug"); });
                AppendLog("数据导出完成");
            }
            catch (Exception ex)
            {
                MyLog.Error(ex);
            }
        }

        private ManualResetEvent _stopReadAirSignal = new ManualResetEvent(false);

        private void ReadAirSignal()
        {
            Task.Run(() =>
            {
                for (int i = 0; i < 4; i++)
                {
                    _airSignals.Add(i, new List<int>());
                }
                while (true)
                {
                    if (_isMonitorAirSignal)
                    {
                        for (int i = 0; i < 4; i++)
                        {
                            _airSignals[i].Add(IoModule.GetDiValue((int)DiDefine.AirPressureSignal1 + i) ? 1 : 0);
                        }
                    }
                    else
                    {
                        _stopReadAirSignal?.Set();
                    }
                    Wait(50);
                }
            });
        }

        private void Wait(int milliseconds)
        {
            Stopwatch sw = Stopwatch.StartNew();
            while (sw.ElapsedMilliseconds < milliseconds)
            {
                Thread.SpinWait(1);
            }
        }

        private void StartMonitorAirSignal()
        {
            MyLog.Info($"{nameof(StartMonitorAirSignal)} start");
            _stopReadAirSignal = new ManualResetEvent(false);
            for (int i = 0; i < _airSignals.Count; i++)
            {
                _airSignals[i].Clear();
            }
            _isMonitorAirSignal = true;
        }

        private readonly Lock _logLocker = new Lock();

        private void AppendLog(string msg)
        {
            lock (_logLocker)
            {
                Application.Current.Dispatcher.Invoke(() =>
                {
                    Log = $"[{_logIndex++}]{msg}";
                    MyLog.Info(msg);
                });
            }
        }

        private void StopMonitorAirSignal()
        {
            _isMonitorAirSignal = false;
            if (_stopReadAirSignal?.WaitOne(300) == false)
            {
                throw new Exception($"{StopMonitorAirSignal}超时");
            }
        }

        private async Task UpdateSystemTime()
        {
            await Task.Delay(1);
            _isRun = true;
            while (_isRun)
            {
                SystemTime = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss");
                await Task.Delay(1000);
            }
        }

        // 自动生成的部分方法（由源码生成器补全）
        partial void OnSelectedProductChanged(string value)
        {
            // 在此处添加回调逻辑
            AppendLog($"机种变更为: {value}");
            try
            {
                // 生成产品参数
                Products.Clear();
                var config = GlobalValue.Config;
                Products.Add(new TestItem { MinLimit = 0, MaxLimit = double.Parse(config.GetParams("PE与防爆外壳接地点阻值上限")), Unit = "Ω", Desc = "接地导通" });
                Products.Add(new TestItem { MaxLimit = -1, MinLimit = double.Parse(config.GetParams($"{SelectedProduct}绝缘阻值下限")), Unit = "MΩ", Desc = "绝缘测试" });
                Products.Add(new TestItem { MinLimit = 0, MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}耐压电流上限")), Unit = "mA", Desc = "耐压测试" });
#if TEST_ALL_CLIENT

                if (_selectedProduct == Jq9602Desc)
                {
                    for (int i = 0; i < 3; i++)
                    {
                        for (int j = 0; j < 2; j++)
                        {
                            Products.Add(new TestItem { MinLimit = double.Parse(config.GetParams($"{SelectedProduct}启动电流下限")), MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}启动电流上限")), Unit = "mA", Desc = $"正向供电阶段{i + 1}-{j + 1}启动电流" });
                            Products.Add(new TestItem { MinLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定电流下限")), MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定电流上限")), Unit = "mA", Desc = $"正向供电阶段{i + 1}-{j + 1}稳定电流" });
                            Products.Add(new TestItem { MinLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定耗时下限")), MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定耗时上限")), Unit = "ms", Desc = $"正向供电阶段{i + 1}-{j + 1}稳定耗时" });
                        }
                        Products.Add(new TestItem { MinLimit = 0, MaxLimit = 0, Desc = $"正向供电阶段{i + 1}气压监控" });
                    }
                    for (int i = 0; i < 3; i++)
                    {
                        for (int j = 0; j < 2; j++)
                        {
                            Products.Add(new TestItem { MinLimit = double.Parse(config.GetParams($"{SelectedProduct}启动电流下限")), MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}启动电流上限")), Unit = "mA", Desc = $"反向供电阶段{i + 1}-{j + 1}启动电流" });
                            Products.Add(new TestItem { MinLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定电流下限")), MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定电流上限")), Unit = "mA", Desc = $"反向供电阶段{i + 1}-{j + 1}稳定电流" });
                            Products.Add(new TestItem { MinLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定耗时下限")), MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定耗时上限")), Unit = "ms", Desc = $"反向供电阶段{i + 1}-{j + 1}稳定耗时" });
                        }
                        Products.Add(new TestItem { MinLimit = 0, MaxLimit = 0, Desc = $"反向供电阶段{i + 1}气压监控" });
                    }
                }
                else
                {
                    for (int i = 0; i < 3; i++)
                    {
                        Products.Add(new TestItem { MinLimit = double.Parse(config.GetParams($"{SelectedProduct}启动电流下限")), MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}启动电流上限")), Unit = "mA", Desc = $"正向供电阶段{i + 1}启动电流" });
                        Products.Add(new TestItem { MinLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定电流下限")), MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定电流上限")), Unit = "mA", Desc = $"正向供电阶段{i + 1}稳定电流" });
                        if (i == 0)
                        {
                            Products.Add(new TestItem { MinLimit = double.Parse(config.GetParams($"{SelectedProduct}首次供电稳定耗时下限")), MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}首次供电稳定耗时上限")), Unit = "ms", Desc = $"正向供电阶段{i + 1}稳定耗时" });
                        }
                        else
                        {
                            Products.Add(new TestItem { MinLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定耗时下限")), MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定耗时上限")), Unit = "ms", Desc = $"正向供电阶段{i + 1}稳定耗时" });
                        }

                        Products.Add(new TestItem { MinLimit = 0, MaxLimit = 0, Desc = $"正向供电阶段{i + 1}气压监控" });
                    }
                    for (int i = 0; i < 3; i++)
                    {
                        Products.Add(new TestItem { MinLimit = double.Parse(config.GetParams($"{SelectedProduct}启动电流下限")), MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}启动电流上限")), Unit = "mA", Desc = $"反向供电阶段{i + 1}启动电流" });
                        Products.Add(new TestItem { MinLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定电流下限")), MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定电流上限")), Unit = "mA", Desc = $"反向供电阶段{i + 1}稳定电流" });
                        Products.Add(new TestItem { MinLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定耗时下限")), MaxLimit = double.Parse(config.GetParams($"{SelectedProduct}稳定耗时上限")), Unit = "ms", Desc = $"反向供电阶段{i + 1}稳定耗时" });

                        Products.Add(new TestItem { MinLimit = 0, MaxLimit = 0, Desc = $"反向供电阶段{i + 1}气压监控" });
                    }
                }

                _phaseAnalyzer.PeakMax = GetConfigDoubleParam($"{SelectedProduct}电流下降起始点上限");
                _phaseAnalyzer.PeakMin = GetConfigDoubleParam($"{SelectedProduct}电流下降起始点下限");
                _phaseAnalyzer.StableMax = GetConfigDoubleParam($"{SelectedProduct}电流下降结束点上限");
                _phaseAnalyzer.StableMin = GetConfigDoubleParam($"{SelectedProduct}电流下降结束点下限");

                if (_selectedProduct == Jq9602Desc)
                {
                    _phaseAnalyzer.StableSampleCount = 5;
                    _phaseAnalyzer.DataIntervalMs = 2;
                    _phaseAnalyzer.FindPeakDataCount = 50;

                    BinaryPulseDetector.MinPulseWidth = 1;
                    BinaryPulseDetector.MinGapWidth = 5;
                    BinaryPulseDetector.RequiredPulseCount = 2;
                }
                else
                {
                    _phaseAnalyzer.StableSampleCount = 5;
                    _phaseAnalyzer.DataIntervalMs = 20;
                    _phaseAnalyzer.FindPeakDataCount = 20;

                    BinaryPulseDetector.MinPulseWidth = 1;
                    BinaryPulseDetector.MinGapWidth = 5;
                    BinaryPulseDetector.RequiredPulseCount = 1;
                }
#endif
                // save config
                GlobalValue.Config.ParamList["当前测试产品类型"] = _selectedProduct;
                GlobalValue.Config.SaveToFile("config.xlsx", "参数配置");
            }
            catch (Exception e)
            {
                AppendLog(e.Message);
                // save config, if save failed (file is using in other process, do nothing)
                MyLog.Error(e);
            }
        }

        [ObservableProperty] private ObservableCollection<DiDoStatus> _diDoStatuses;
        [ObservableProperty] private string _licenseMessage;
        [ObservableProperty] private string _licenseSn;
        [ObservableProperty] private string _log = string.Empty;
        [ObservableProperty] private string _systemTime = string.Empty;
        [ObservableProperty] private string _selectedProduct = "";
        [ObservableProperty] private List<string> _productTypeList;
        [ObservableProperty] private Products _products;
        [ObservableProperty] private ObservableCollection<bool?> _totalResult;
        [ObservableProperty] private TestItem? _selectedItem;
        [ObservableProperty] private int _passCount;
        [ObservableProperty] private int _ngCount;
        [ObservableProperty] private string _title;

        private CancellationTokenSource _emgStopTokenSource;

        private readonly Dictionary<string, List<double>> _dataDtail = new Dictionary<string, List<double>>();
        private readonly Dictionary<int, List<int>> _airSignals = new Dictionary<int, List<int>>();
        private bool _isMonitorAirSignal;
        private const int TimeDelay = 200;
        private bool _isTesting;
        private bool _isBusy;
        private bool _isRun = true;
        private bool _isEmgStop;
        private int _logIndex = 0;
        private const string Jq9602Desc = "JQ9602-DC";
        private readonly PhaseAnalyzer _phaseAnalyzer;

        public MainViewModel()
        {
            LicenseSn = GlobalValue.LicenseSn;
            LicenseMessage = GlobalValue.LicenseMessage;
            _emgStopTokenSource = new CancellationTokenSource();
            TotalResult = new ObservableCollection<bool?>();
            for (int i = 0; i < TestItem.StationCount; i++)
            {
                TotalResult.Add(null);
            }
            BindingOperations.EnableCollectionSynchronization(TotalResult, new object());
            _diDoStatuses = new ObservableCollection<DiDoStatus>();
            ProductTypeList = ["JQ9602-DC", "JQ9603-AC"];
            Products = new Products();
            _phaseAnalyzer = new PhaseAnalyzer();
            Title = "JQ9602/JQ9603 FCT测试系统（一检）";
#if TEST_ALL_CLIENT
            Title = "JQ9602/JQ9603 FCT测试系统（终检）";
#endif
        }
    }
}